package com.huangkailong.designpattern.singleton;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.util.Objects;

/**
 * 内部类方式实现单例模式.
 *
 * @author huangkl
 * @since 1.0.0
 */
public class InnerClassSingleton implements Serializable {
    private static final long serialVersionUID = 615569941966432331L;

    private InnerClassSingleton() {
        // 防止反射多次创建
        if (Objects.nonNull(Instance.instance)) {
            throw new IllegalStateException("InnerClassSingleton 只允许被创建一次对象!");
        }
    }

    /**
     * 获取 {@link InnerClassSingleton} 实例.
     *
     * @return {@link InnerClassSingleton} 实例
     */
    public static InnerClassSingleton getInstance() {
        return Instance.instance;
    }

    /**
     * 测试.
     */
    public static void main(String[] args) {
        System.out.println("对象比较结果：");
        System.out.println(InnerClassSingleton.getInstance() == InnerClassSingleton.getInstance());
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)
        ) {
            objectOutputStream.writeObject(InnerClassSingleton.getInstance());

            try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
                byteArrayOutputStream.toByteArray());
                 ObjectInputStream objectInputStream = new ObjectInputStream(
                     byteArrayInputStream)) {
                Object o = objectInputStream.readObject();
                System.out.println("序列化结果:");
                System.out.println(InnerClassSingleton.getInstance() == o);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            Constructor<InnerClassSingleton> constructor =
                InnerClassSingleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            constructor.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 解决序列化和反序列化后破坏了单例模式.
     *
     * @return {@link InnerClassSingleton} 实例
     */
    public Object readResolve() {
        return Instance.instance;
    }

    private static class Instance {
        static InnerClassSingleton instance = new InnerClassSingleton();
    }
}
